package com.gitee.feizns.reflect;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.function.Predicate;
import java.util.stream.Stream;

/**
 * 方法.
 * @author feizns
 * @since 2019/5/15
 */
public abstract class MethodUtils {

    /**
     * 获取方法
     * @param obj
     * @param name
     * @return
     */
    public static final Method getDeclared(Object obj, String name, Class<?>... parameterTypes) {
        return getDeclared(obj.getClass(), name, parameterTypes);
    }

    /**
     * 筛选所有的方法
     * @param type
     * @param filter
     * @return
     */
    public static final Stream<Method> getDeclared(Class<?> type, Predicate<Method> filter) {
        Stream.Builder<Method> builder = Stream.builder();
        while ( type != null ) {
            Arrays.stream(type.getDeclaredMethods()).forEach(method -> {
                if ( filter.test(method) ) {
                    builder.add(method);
                }
            });
            type = type.getSuperclass();
        }
        return builder.build();
    }

    /**
     * 获取方法
     * @param type
     * @param name
     * @param parameterTypes
     * @return
     */
    public static final Method getDeclared(Class<?> type, String name, Class<?>... parameterTypes) {
        while ( type != null ) {
            try {
                return type.getDeclaredMethod(name, parameterTypes);
            } catch (NoSuchMethodException e) {
                type = type.getSuperclass();
            }
        }
        return null;
    }

    /**
     * 获取公共方法
     * @param obj
     * @param name
     * @param parameterTypes
     * @return
     */
    public static final Method get(Object obj, String name, Class<?>... parameterTypes) {
        return get(obj.getClass(), name, parameterTypes);
    }

    /**
     * 获取公共方法
     * @param type
     * @param name
     * @param parameterTypes
     * @return
     */
    public static final Method get(Class<?> type, String name, Class<?>... parameterTypes) {
        try {
            Method method = type.getMethod(name, parameterTypes);
            method.setAccessible(true);
            return method;
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

    /**
     * 自定义查找规则
     * @param type
     * @param filter
     * @return
     */
    public static final Stream<Method> get(Class<?> type, Predicate<Method> filter) {
        return Arrays.stream(type.getMethods()).filter(filter);
    }

    /**
     * 调用方法
     * @param obj
     * @param name
     * @param params
     * @return
     */
    public static final Object invoke(Object obj, String name, Object... params) {
        try {
            return obj.getClass().getMethod(name, ClassUtils.getClasses(params)).invoke(obj, params);
        } catch (ReflectiveOperationException e) {
            return null;
        }
    }

    /**
     * 调用方法
     * @param method
     * @param params
     * @return
     */
    public static final Object invoke(Method method, Object... params) {
        try {
            method.setAccessible(true);
            return method.invoke(null, params);
        } catch (ReflectiveOperationException e) {
            return null;
        }
    }

    /**
     * 调用方法
     * @param method
     * @param params
     * @return
     */
    public static final Object invoke(Object obj, Method method, Object... params) {
        try {
            method.setAccessible(true);
            return method.invoke(obj, params);
        } catch (ReflectiveOperationException e) {
            return null;
        }
    }

}
